package main

import (
	"database/sql"
	"encoding/json"
	"log"
	"os"
	"time"

	"github.com/hyahm/goconfig"
	"github.com/hyahm/golog"
	"github.com/hyahm/gomysql"
	"github.com/hyahm/scs/client"
)

type Access struct {
	User          string            `json:"user"`            // User authenticating
	Pass          string            `json:"pass"`            // Password used for authentication
	Fs            string            `json:"fs"`              // Backend used for accessing file
	Params        map[string]string `json:"params"`          // Backend parameters
	Logging       Logging           `json:"logging"`         // Logging parameters
	ReadOnly      bool              `json:"read_only"`       // Read-only access
	Shared        bool              `json:"shared"`          // Shared FS instance
	SyncAndDelete *SyncAndDelete    `json:"sync_and_delete"` // Local empty directory and synchronization
}

// SyncAndDelete provides
type SyncAndDelete struct {
	Enable    bool   `json:"enable"`    // Instant write
	Directory string `json:"directory"` // Directory
}

// PortRange defines a port-range
// ... used only for the passive transfer listening range at this stage.
type PortRange struct {
	Start int `json:"start"` // Start of the range
	End   int `json:"end"`   // End of the range
}

// Logging defines how we will log accesses
type Logging struct {
	FtpExchanges bool `json:"ftp_exchanges"` // Log all ftp exchanges
	FileAccesses bool `json:"file_accesses"` // Log all file accesses
}

// TLS define the TLS Config
type TLS struct {
	ServerCert *ServerCert `json:"server_cert"` // Server certificates
}

// ServerCert defines the TLS server certificate config
type ServerCert struct {
	Cert string `json:"cert"` // Public certificate(s)
	Key  string `json:"key"`  // Private key
}

// Content defines the content of the config file
type Content struct {
	Version                  int        `json:"version"`                     // File format version
	ListenAddress            string     `json:"listen_address"`              // Address to listen on
	PublicHost               string     `json:"public_host"`                 // Public host to listen on
	MaxClients               int        `json:"max_clients"`                 // Maximum clients who can connect
	Accesses                 []*Access  `json:"accesses"`                    // Accesses offered to users
	PassiveTransferPortRange *PortRange `json:"passive_transfer_port_range"` // Listen port range
	Logging                  Logging    `json:"logging"`                     // Logging parameters
	TLS                      *TLS       `json:"tls"`                         // TLS Config
}

type Config struct {
	ID     int64   `json:"id" db:"id,default"`
	Name   string  `json:"name" db:"name"`
	Config Content `json:"config" db:"config"`
	New    bool    `json:"new" db:"new"`
}

// 读取mysql的配置， 如果有更新，那么更新ftpserver的配置文件，并且重启ftpserver
var DB *gomysql.Db

func main() {
	goconfig.InitConf("ftputil.ini", goconfig.INI)
	InitMysql()
	b, err := os.ReadFile(goconfig.ReadString("ftpconfig", "ftpserver.json"))
	if err != nil {
		log.Fatal(err)
	}
	fc := Config{
		Name: "ftpserver",
	}
	err = json.Unmarshal(b, &fc.Config)
	if err != nil {
		log.Fatal(err)
	}
	// 插入配置文件
	// 查询数据， 如果没有就插入，如果存在就修改
	var id int64
	err = DB.GetOne("select id from config where name='ftpserver'").Scan(&id)
	if err == nil {
		_, err = DB.UpdateInterface(fc, "update config set $set where name='ftpserver'")
	} else if err != nil && err == sql.ErrNoRows {
		err = DB.InsertInterfaceWithoutID(fc, "insert into config($key) values($value)")
	}

	if err != nil {
		log.Fatal(err)
	}
	for {
		time.Sleep(time.Millisecond * 10)
		c := &Config{}
		err := DB.Select(&c, "select * from config where name='ftpserver'")
		if err != nil {
			golog.Error(err)
		}

		if c.New {
			b, err := json.MarshalIndent(c.Config, "", "\t")
			if err != nil {
				golog.Error(err)
			} else {
				err = os.WriteFile(goconfig.ReadString("ftpconfig", "ftpserver.json"), b, 0644)
				if err != nil {
					log.Println(err)
				}
				// 重启 ftpserver
				cli := client.NewClient()
				cli.Domain = goconfig.ReadString("scsDomain", "")
				cli.Token = goconfig.ReadString("scsToken", "")
				cli.Pname = goconfig.ReadString("servername", "ftp_server")
				cli.Name = cli.Pname + "_0"
				res, err := cli.RestartName()
				if err == nil {
					// 修改完成后，配置文件是最新的了
					_, err := DB.Update("update config set new=false where name='ftpserver'")
					if err != nil {
						log.Println(err)
					}
				}
				if err != nil {
					log.Println(err)
				}
				log.Println(res)
			}
		}
	}
}

func InitMysql() error {
	// 初始化mysql
	conf := &gomysql.Sqlconfig{
		Host:         goconfig.ReadString("host", "192.168.50.250"),
		Port:         goconfig.ReadInt("port", 3306),
		UserName:     goconfig.ReadString("username", "test"),
		DbName:       goconfig.ReadString("db", "shop"),
		Password:     goconfig.ReadPassword("password", "123456"),
		MaxOpenConns: 1,
		MaxIdleConns: 1,
		Charset:      "utf8mb4",
	}
	golog.Infof("%#v", *conf)
	var err error
	DB, err = conf.NewDb()
	if err != nil {
		return err
	}
	return DB.Ping()
}
